{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Execute this cell to install dependencies\n",
    "%pip install sf-hamilton[visualization]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Monitor Hamilton with OpenTelemetry, OpenLLMetry and Traceloop [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/dagworks-inc/hamilton/blob/main/examples/LLM_Workflows/observability_openllmetry/notebook.ipynb) [![GitHub badge](https://img.shields.io/badge/github-view_source-2b3137?logo=github)](https://github.com/apache/hamilton/blob/main/examples/LLM_Workflows/observability_openllmetry/notebook.ipynb)\n",
    "\n",
    "\n",
    "\n",
    "It will showcase how the [OpenTelemetry](https://opentelemetry.io/) plugin for Hamilton can trace node and using [OpenLLMetry](https://github.com/traceloop/openllmetry) allows to automatically trace popular LLM components. This example uses [Traceloop](https://www.traceloop.com/) as a destination for telemetry, but other [open-source options are available](https://opentelemetry.io/ecosystem/vendors/) (Jaeger, Elastic, Clickhouse, Grafana, etc.)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "from hamilton import driver\n",
    "from hamilton.plugins import h_opentelemetry\n",
    "from traceloop.sdk import Traceloop\n",
    "\n",
    "%load_ext hamilton.plugins.jupyter_magic"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Define a dataflow\n",
    "The next cell creates a Python module named `llm_dataflow` and defines a dataflow that creates an OpenAI client and queries the chat completions endpoint to center an HTML `<div>` tag.\n",
    "\n",
    "You'll notice that nothing special is added to enable tracing"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/svg+xml": [
       "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
       "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
       " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
       "<!-- Generated by graphviz version 2.43.0 (0)\n",
       " -->\n",
       "<!-- Title: %3 Pages: 1 -->\n",
       "<svg width=\"282pt\" height=\"167pt\"\n",
       " viewBox=\"0.00 0.00 282.00 167.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
       "<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 163)\">\n",
       "<title>%3</title>\n",
       "<polygon fill=\"white\" stroke=\"transparent\" points=\"-4,4 -4,-163 278,-163 278,4 -4,4\"/>\n",
       "<g id=\"clust1\" class=\"cluster\">\n",
       "<title>cluster__legend</title>\n",
       "<polygon fill=\"#ffffff\" stroke=\"black\" points=\"8,-74 8,-151 104,-151 104,-74 8,-74\"/>\n",
       "<text text-anchor=\"middle\" x=\"56\" y=\"-135.8\" font-family=\"Helvetica,sans-Serif\" font-size=\"14.00\">Legend</text>\n",
       "</g>\n",
       "<!-- universal_truth -->\n",
       "<g id=\"node1\" class=\"node\">\n",
       "<title>universal_truth</title>\n",
       "<path fill=\"#b4d8e4\" stroke=\"black\" d=\"M262,-64C262,-64 145,-64 145,-64 139,-64 133,-58 133,-52 133,-52 133,-12 133,-12 133,-6 139,0 145,0 145,0 262,0 262,0 268,0 274,-6 274,-12 274,-12 274,-52 274,-52 274,-58 268,-64 262,-64\"/>\n",
       "<text text-anchor=\"start\" x=\"144\" y=\"-42.8\" font-family=\"Helvetica,sans-Serif\" font-weight=\"bold\" font-size=\"14.00\">universal_truth</text>\n",
       "<text text-anchor=\"start\" x=\"194\" y=\"-14.8\" font-family=\"Helvetica,sans-Serif\" font-style=\"italic\" font-size=\"14.00\">str</text>\n",
       "</g>\n",
       "<!-- llm_client -->\n",
       "<g id=\"node2\" class=\"node\">\n",
       "<title>llm_client</title>\n",
       "<path fill=\"#b4d8e4\" stroke=\"black\" d=\"M92,-64C92,-64 20,-64 20,-64 14,-64 8,-58 8,-52 8,-52 8,-12 8,-12 8,-6 14,0 20,0 20,0 92,0 92,0 98,0 104,-6 104,-12 104,-12 104,-52 104,-52 104,-58 98,-64 92,-64\"/>\n",
       "<text text-anchor=\"start\" x=\"19\" y=\"-42.8\" font-family=\"Helvetica,sans-Serif\" font-weight=\"bold\" font-size=\"14.00\">llm_client</text>\n",
       "<text text-anchor=\"start\" x=\"30\" y=\"-14.8\" font-family=\"Helvetica,sans-Serif\" font-style=\"italic\" font-size=\"14.00\">OpenAI</text>\n",
       "</g>\n",
       "<!-- llm_client&#45;&gt;universal_truth -->\n",
       "<g id=\"edge1\" class=\"edge\">\n",
       "<title>llm_client&#45;&gt;universal_truth</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M104.24,-32C110.09,-32 116.19,-32 122.36,-32\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"122.78,-35.5 132.78,-32 122.78,-28.5 122.78,-35.5\"/>\n",
       "</g>\n",
       "<!-- function -->\n",
       "<g id=\"node3\" class=\"node\">\n",
       "<title>function</title>\n",
       "<path fill=\"#b4d8e4\" stroke=\"black\" d=\"M84,-119.5C84,-119.5 28,-119.5 28,-119.5 22,-119.5 16,-113.5 16,-107.5 16,-107.5 16,-94.5 16,-94.5 16,-88.5 22,-82.5 28,-82.5 28,-82.5 84,-82.5 84,-82.5 90,-82.5 96,-88.5 96,-94.5 96,-94.5 96,-107.5 96,-107.5 96,-113.5 90,-119.5 84,-119.5\"/>\n",
       "<text text-anchor=\"middle\" x=\"56\" y=\"-97.3\" font-family=\"Helvetica,sans-Serif\" font-size=\"14.00\">function</text>\n",
       "</g>\n",
       "</g>\n",
       "</svg>\n"
      ],
      "text/plain": [
       "<graphviz.graphs.Digraph at 0x7f78c554f050>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "%%cell_to_module llm_dataflow -d\n",
    "import openai\n",
    "\n",
    "def llm_client() -> openai.OpenAI:\n",
    "    return openai.OpenAI()\n",
    "\n",
    "def universal_truth(llm_client: openai.OpenAI) -> str:\n",
    "    response = llm_client.chat.completions.create(\n",
    "        model=\"gpt-4o-mini\",\n",
    "        messages=[\n",
    "            {\"role\": \"system\", \"content\": \"You are a benevolent all-knowning being\"},\n",
    "            {\"role\": \"user\", \"content\": \"Please center my HTML <div> tag\"},\n",
    "        ],\n",
    "    )\n",
    "    return str(response.choices[0].message.content)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Build the dataflow\n",
    "The Hamilton `Builder` object takes the previously defined dataflow via `.with_modules(llm_dataflow)`. Then, we pass the `OpenTelemetryTracer` object via `.with_adapters()` to trace dataflow execution. Make sure to call `Traceloop.init()` before creating the `OpenTelemetryTracer`.\n",
    "\n",
    "You'll need to set your `OPENAI_API_KEY` and your `TRACELOOP_API_KEY` to run the cell."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "os.environ[\"OPENAI_API_KEY\"] = ...\n",
    "os.environ[\"TRACELOOP_API_KEY\"] = ..."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[32mTraceloop syncing configuration and prompts\u001b[39m\n",
      "\u001b[32mTraceloop exporting traces to https://api.traceloop.com authenticating with bearer token\n",
      "\u001b[39m\n"
     ]
    }
   ],
   "source": [
    "Traceloop.init()\n",
    "\n",
    "dr = (\n",
    "    driver.Builder()\n",
    "    .with_modules(llm_dataflow)\n",
    "    .with_adapters(h_opentelemetry.OpenTelemetryTracer())\n",
    "    .build()\n",
    ")\n",
    "\n",
    "# If you wanted to use another OpenTelemetry destination such as the\n",
    "# open-source Jaeger, setup the container locally and use the following code\n",
    "\n",
    "# from opentelemetry import trace\n",
    "# from opentelemetry.sdk.trace import TracerProvider\n",
    "# from opentelemetry.sdk.trace.export import SimpleSpanProcessor\n",
    "# from opentelemetry.exporter.jaeger import JaegerExporter\n",
    "\n",
    "# jaeger_exporter = JaegerExporter(agent_host_name='localhost', agent_port=5775)\n",
    "# span_processor = SimpleSpanProcessor(jaeger_exporter)\n",
    "# provider = TracerProvider(active_span_processor=span_processor)\n",
    "# trace.set_tracer_provider(provider)\n",
    "\n",
    "results = dr.execute([\"universal_truth\"])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "To center an HTML `<div>` element, you can use CSS. There are several methods to achieve this, depending on whether you want to center it horizontally, vertically, or both. Here are a few common methods:\n",
      "\n",
      "### Centering Horizontally\n",
      "\n",
      "One of the simplest ways to center a `<div>` horizontally is to set its width, and then use `margin: auto;`. Here's an example:\n",
      "\n",
      "```html\n",
      "<!DOCTYPE html>\n",
      "<html lang=\"en\">\n",
      "<head>\n",
      "    <meta charset=\"UTF-8\">\n",
      "    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n",
      "    <title>Center Div</title>\n",
      "    <style>\n",
      "        .centered-div {\n",
      "            width: 50%; /* Set a width */\n",
      "            margin: 0 auto; /* Center horizontally */\n",
      "            background-color: lightblue; /* Optional: Background color */\n",
      "            padding: 20px; /* Optional: Padding */\n",
      "            text-align: center; /* Optional: Center text */\n",
      "        }\n",
      "    </style>\n",
      "</head>\n",
      "<body>\n",
      "    <div class=\"centered-div\">\n",
      "        This div is centered horizontally!\n",
      "    </div>\n",
      "</body>\n",
      "</html>\n",
      "```\n",
      "\n",
      "### Centering Vertically and Horizontally\n",
      "\n",
      "To center a `<div>` both vertically and horizontally, you can use Flexbox or CSS Grid. Here's an example using Flexbox:\n",
      "\n",
      "```html\n",
      "<!DOCTYPE html>\n",
      "<html lang=\"en\">\n",
      "<head>\n",
      "    <meta charset=\"UTF-8\">\n",
      "    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n",
      "    <title>Center Div</title>\n",
      "    <style>\n",
      "        body {\n",
      "            display: flex;\n",
      "            justify-content: center; /* Center horizontally */\n",
      "            align-items: center; /* Center vertically */\n",
      "            height: 100vh; /* Full viewport height */\n",
      "            margin: 0; /* Remove default margin */\n",
      "        }\n",
      "\n",
      "        .centered-div {\n",
      "            width: 50%; /* Set a width */\n",
      "            background-color: lightblue; /* Optional: Background color */\n",
      "            padding: 20px; /* Optional: Padding */\n",
      "            text-align: center; /* Optional: Center text */\n",
      "        }\n",
      "    </style>\n",
      "</head>\n",
      "<body>\n",
      "    <div class=\"centered-div\">\n",
      "        This div is centered both vertically and horizontally!\n",
      "    </div>\n",
      "</body>\n",
      "</html>\n",
      "```\n",
      "\n",
      "### Centering with CSS Grid\n",
      "\n",
      "Here's another way to center using CSS Grid:\n",
      "\n",
      "```html\n",
      "<!DOCTYPE html>\n",
      "<html lang=\"en\">\n",
      "<head>\n",
      "    <meta charset=\"UTF-8\">\n",
      "    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n",
      "    <title>Center Div</title>\n",
      "    <style>\n",
      "        body {\n",
      "            display: grid;\n",
      "            height: 100vh; /* Full viewport height */\n",
      "            place-items: center; /* Center both vertically and horizontally */\n",
      "            margin: 0; /* Remove default margin */\n",
      "        }\n",
      "\n",
      "        .centered-div {\n",
      "            width: 50%; /* Set a width */\n",
      "            background-color: lightblue; /* Optional: Background color */\n",
      "            padding: 20px; /* Optional: Padding */\n",
      "            text-align: center; /* Optional: Center text */\n",
      "        }\n",
      "    </style>\n",
      "</head>\n",
      "<body>\n",
      "    <div class=\"centered-div\">\n",
      "        This div is centered using CSS Grid!\n",
      "    </div>\n",
      "</body>\n",
      "</html>\n",
      "```\n",
      "\n",
      "Choose the method that best fits your layout needs!\n"
     ]
    }
   ],
   "source": [
    "print(results[\"universal_truth\"])"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "venv",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
